package owg.util.awt;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JComboBox;

public class StringConstantEditor extends TypeEditor<String> implements ActionListener
	{
	static final long serialVersionUID = 2704835030524222876L;
	
	JComboBox<String> box;
	String value;
	boolean ignoreEvents = false;
	boolean nullAllowed;
	Color origcolor;
	
	/**
	 * 
	 * @param initialValue The initially chosen value. Should be one of the constants.
	 * If it is not in the list, it will default to null: 
	 * If null, "null" will be selected if "addNull" is true, the first element otherwise.
	 * @param constants The list of choosable constants
	 * @param addNull Whether to add the string "null" to the list of constants. If "null" is selected, getValue() returns null.
	 */
	public StringConstantEditor(String initialValue, String[] constants, boolean addNull)
		{
		super(String.class);
		String val = null;
		for(String s:constants)
			{
			if(s.equals(initialValue))
				val = s;
			}
		
		box = new JComboBox<String>(constants);
		nullAllowed = addNull;
		if(addNull)
			{
			String nul = "null";
			box.addItem(nul);
			if(val == null)
				val = nul;
			}
		else if(val == null)
			val = constants[0];
		
		origcolor = box.getBackground();
		setValue(val, false);
		add(box);
		box.addActionListener(this);
		}
	/**If the value is not in the list:
	 * If null is allowed, "null" is selected.
	 * Otherwise, the selection remains unchanged.*/
	private void setValue(String val, boolean fire)
		{
		if(val == null)
			{
			if(nullAllowed)
				val = "null";
			else
				throw new IllegalArgumentException("This string cannot be null");
			}
		String pVal = value;
		ignoreEvents = true;
		
		for(int i = 0; i<box.getItemCount(); i++)
			{
			if(box.getItemAt(i).equals(val))
				val = box.getItemAt(i);
			}
		box.setSelectedItem(val);
		if(!box.getSelectedItem().equals(val))
			{
			if(nullAllowed)
				val = "null";
			else
				val = pVal;
			box.setSelectedItem(val);
			}
		value = val;
			
		ignoreEvents = false;
		if(fire && ((pVal == null && value!=null) || !pVal.equals(value)))
			{
			fireActionEvents();
			flash(Color.GREEN);
			}
		}

	@Override
	public void actionPerformed(ActionEvent e)
		{
		if(!ignoreEvents)
			parseValue();
		}

	private void parseValue()
		{
		try {
			setValue(box.getItemAt(box.getSelectedIndex()), true);
			}
		catch(IllegalArgumentException e)
			{
			flash(Color.RED);
			setValue(box.getItemAt(0), false);
			}
		}

	synchronized void color(Color color)
		{
		box.setBackground(color);
		}

	private void flash(Color color)
		{
		color(color);
		flashThread(new Runnable(){public void run(){color(origcolor);}}, 33);
		}
	/**Returns null if the string "null" is selected. Otherwise, returns the selected string as is.*/
	@Override
	public String getValue()
		{
		if(value.equals("null"))
			return null;
		else
			return (String)value;
		}
	

	@Override
	public void setValue(String val)
		{
		setValue(val, false);
		}

	public int getSelectedIndex()
		{
		return box.getSelectedIndex();
		}
	
	@Override
	public void setToolTipTextToSubComponents(String text)
		{
		box.setToolTipText(text);
		}
	

	@Override
	public void setSubComponentsEnabled(boolean en)
		{
		box.setEnabled(en);
		}

	public int getNumValues()
		{
		return box.getItemCount();
		}
	@Override
	public boolean shouldGrowHeight()
		{
		return true;
		}
	}
